feat: Invoked IText2SqlHook.SqlExecuting in SqlSelectFn and ExecuteQueryFn - #1392
Conversation
…eryFn before deserializing the function args, so hooks can rewrite the SQL statements (e.g. inject trace tags) prior to execution.
PR Summary by QodoInvoke Text2Sql SqlExecuting hook before function-arg deserialization
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1. Hook exceptions escape handling
|
| var dbHook = _services.GetRequiredService<IText2SqlHook>(); | ||
| // The hook may rewrite message.FunctionArgs (e.g. tag the statements for | ||
| // traceability), so it must run before the args are deserialized. | ||
| await dbHook.SqlExecuting(message); |
There was a problem hiding this comment.
1. Hook exceptions escape handling 🐞 Bug ☼ Reliability
SqlExecuting is invoked before existing error-handling paths (and SqlSelectFn has no local handling at all), so a throwing hook can abort execution without producing the usual controlled message.Content/StopCompletion outcomes. This creates a new unhandled-exception path introduced by this PR.
Agent Prompt
### Issue description
`IText2SqlHook.SqlExecuting` is now awaited before the function’s existing try/catch handling (and `SqlSelectFn` has none), so any hook exception can bubble out and bypass normal failure reporting.
### Issue Context
The codebase already has a standard safe hook-dispatch mechanism (`HookEmitter.Emit`) that catches and logs hook exceptions per hook.
### Fix Focus Areas
- src/Plugins/BotSharp.Plugin.SqlDriver/Functions/ExecuteQueryFn.cs[25-35]
- src/Plugins/BotSharp.Plugin.SqlDriver/Functions/SqlSelectFn.cs[16-34]
- src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs[38-64]
### Proposed fix
Wrap `SqlExecuting` invocation with error handling consistent with the rest of the system. Prefer using `HookEmitter.Emit<IText2SqlHook>(...)` (which already catches/logs hook exceptions) or add a local try/catch around `SqlExecuting` that sets `message.Content`, `message.StopCompletion`, and returns `false` in a controlled way.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| var dbHook = _services.GetRequiredService<IText2SqlHook>(); | ||
| // The hook may rewrite message.FunctionArgs (e.g. tag the statement for | ||
| // traceability), so it must run before the args are deserialized. | ||
| await dbHook.SqlExecuting(message); | ||
|
|
There was a problem hiding this comment.
2. Multi-hook dispatch bypassed 🐞 Bug ≡ Correctness
SqlExecuting is invoked on a single IText2SqlHook resolved via GetRequiredService, so other registered/matching hooks won’t receive SqlExecuting and cannot rewrite FunctionArgs. This is inconsistent with the repo’s hook infrastructure which supports multiple hooks per agent via GetHooks/HookEmitter.Emit.
Agent Prompt
### Issue description
`SqlExecuting` is called on a single resolved `IText2SqlHook`, but the repo supports multiple hooks per agent. As a result, only one registered hook receives the new `SqlExecuting` event, and others cannot apply SQL rewrites/tags.
### Issue Context
- `HookProvider.GetHooks<T>` is built on `GetServices<T>()`, enabling multiple hooks.
- `SqlDriverPlanningHook` already uses `HookEmitter.Emit<IText2SqlHook>` for `SqlGenerated`.
### Fix Focus Areas
- src/Plugins/BotSharp.Plugin.SqlDriver/Functions/SqlSelectFn.cs[16-34]
- src/Plugins/BotSharp.Plugin.SqlDriver/Functions/ExecuteQueryFn.cs[25-35]
- src/Infrastructure/BotSharp.Abstraction/Hooks/HookProvider.cs[8-12]
- src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs[25-28]
### Proposed fix
Dispatch `SqlExecuting` through `HookEmitter.Emit<IText2SqlHook>(_services, hook => hook.SqlExecuting(message), message.CurrentAgentId)` (or iterate `_services.GetHooks<IText2SqlHook>(message.CurrentAgentId)`). Keep the single-hook resolution only for `GetDatabaseType` / `GetConnectionString` if the design requires a single authoritative provider.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
feat: Invoked
IText2SqlHook.SqlExecutinginSqlSelectFnandExecuteQueryFnbefore deserializing the function args, so hooks can rewrite the SQL statements (e.g. inject trace tags) prior to execution.